package tx;

import org.junit.Test;
import org.springframework.transaction.support.DefaultTransactionStatus;
import tx.service.UserService;
import tx.service.UserTest1Service;

import java.io.IOException;

/**
 * @author jackcfan
 * @date 22/10/1
 */
public class TransactionTest extends BaseTest{

  @Test
  public void programedTransactionTest(){
    UserService userService = context.getBean(UserService.class);
    userService.programedTransaction();
  }

  @Test
  public void proxyUpdate(){
    // Cglib 动态代理对象，
    UserService userService = context.getBean(UserService.class);
    userService.proxyUpdate();
  }

  @Test
  public void normalTargetUpdate(){
    UserService userService = context.getBean(UserService.class);
    userService.normalTargetUpdate();
  }

  /**
   * ServiceA 开始事务，调用 ServiceB，且ServiceB也开启了事务
   * 如果 ServiceB 抛出了 RuntimeException ,则会把当前事务标记为或回滚
   * 即使 ServiceA 调用 ServiceB 时使用了 catch，但是当前事务已经被标记，只能回滚
   * 所以所有数据全被回滚
   *
   * 多层嵌套事务中，如果使用了默认的事务传播方式，当内层事务抛出异常，外层事务捕捉并正常执行完毕时，就会报出rollback-only异常
   * 无论外层事务和内层事务任何一个出现异常，那么所有的sql都不会执行
   * Transaction rolled back because it has been marked as rollback-only
   * {@link org.springframework.transaction.support.AbstractPlatformTransactionManager#processRollback(DefaultTransactionStatus, boolean)}
   * {@link org.springframework.jdbc.datasource.DataSourceTransactionManager#doSetRollbackOnly(DefaultTransactionStatus)}
   * 结果：没有数据被插入
   * */
  @Test
  public void transactionNestTest1(){
    UserTest1Service service = context.getBean(UserTest1Service.class);
    service.methodA();
  }

  /**
   * ServiceB 抛出了 IOException 异常，非 RuntimeException，即使不 catch 也不会回滚事务
   * 结果：插入了2条数据
   * */
  @Test
  public void transactionNestTest2() throws IOException {
    UserTest1Service service = context.getBean(UserTest1Service.class);
    service.methodB();
  }

  /**
   * ServiceA 开始事务，调用 ServiceB，但是 ServiceB 并没有开启了事务（ServiceB 没有通过代理对象调用）
   * ServiceB 抛出了 RuntimeException ,不会对当前事务状态做修改
   * ServiceA catch 了 ServiceB 的异常，不会回滚
   *
   * 结果：插入了2条数据
   * */
  @Test
  public void transactionNestTest3() throws IOException {
    UserTest1Service service = context.getBean(UserTest1Service.class);
    service.methodC();
  }
}
